/*
' Family Tree Library -  http://www.keydance.com
' Copyright (c) 2006
' by Charles Nurse
*/

#region Using directives

using System;

using FamilyTreeProject.Framework.Enums;
using System.Text.RegularExpressions;
using System.Text;

#endregion

namespace FamilyTreeProject.Framework.Structures
{
    /// <summary>
    /// The Name class models the GEDCOM Name Structure
    /// </summary>
    public class Name : IComparable, IEquatable<Name>, ICloneable, IComparable<Name>, IFormattable
    {
        #region Public Static Fields and Constants

        public static readonly Name Empty = new Name();

        #endregion

        #region Private Members

        private string givenName;		// GIVN
        private string lastName; 	    // SURN
        private string nickName;	    // NICK
        private string prefix;		    // NPFX
        private string suffix;		    // NSFX
        private string lastNamePrefix;  // SPFX

        #endregion

        #region Constructors

        public Name() { }

        public Name(string prefix, string givenName, string lastNamePrefix, string lastName, string suffix, string nickName)
        {
            this.givenName = givenName;
            this.lastName = lastName;
            this.nickName = nickName;
            this.prefix = prefix;
            this.suffix = suffix;
            this.lastNamePrefix = lastNamePrefix;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the First Name
        /// </summary>
        public string GivenName
        {
            get { return givenName; }
            set { givenName = value; }
        }

        /// <summary>
        /// Gets or sets the Last Name
        /// </summary>
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }

        /// <summary>
        /// Gets or sets the NickName
        /// </summary>
        public string NickName
        {
            get { return nickName; }
            set { nickName = value; }
        }

        /// <summary>
        /// Gets or sets the Prefix
        /// </summary>
        public string Prefix
        {
            get { return prefix; }
            set { prefix = value; }
        }

        /// <summary>
        /// Gets or sets the Suffix
        /// </summary>
        public string Suffix
        {
            get { return suffix; }
            set { suffix = value; }
        }

        /// <summary>
        /// Gets or sets the LastNamePrefix
        /// </summary>
        public string LastNamePrefix
        {
            get { return lastNamePrefix; }
            set { lastNamePrefix = value; }
        }

        #endregion

        #region Private Methods

        private string EvaluateFormatToken(Match token)
        {
            switch (token.Value.ToLower())
            {
                case "g": return this.GivenName;
                case "l": return this.LastName;
                case "n": return this.NickName;
                case "p": return this.Prefix;
                case "s": return this.Suffix;
                case "x": return this.LastNamePrefix;
                default: return String.Empty;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Determines if two instances of a Name are the same
        /// </summary>
        public override bool Equals(object obj)
        {
            if (obj is Name)
                return Equals((Name)obj);
            else
                return false;
        }

        /// <summary>
        /// This method gets a hash code for the object
        /// </summary>
        /// <returns>An integer</returns>
        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        /// <summary>
        /// This method overrides the default ToString method to return
        /// a string representation of the Name object
        /// </summary>
        /// <returns>The formatted string</returns>
        public override string ToString()
        {
            return ToString(NameFormat.LastFirstShort);
        }

        /// <summary>
        /// Provides a string representation of the Name object based on a NameFormat
        /// </summary>
        /// <param name="format">The format to use</param>
        /// <returns>The formatted string</returns>
        public string ToString(NameFormat format)
        {
            string result = "";
            switch (format)
            {
                case NameFormat.FirstLastLong:
                    result = (String.IsNullOrEmpty(Prefix)) ? "" : Prefix + " ";
                    result += (String.IsNullOrEmpty(GivenName)) ? "" : GivenName + " ";
                    result += (String.IsNullOrEmpty(NickName)) ? "" : " {" + NickName + "} ";
                    result += (String.IsNullOrEmpty(LastNamePrefix)) ? "" : LastNamePrefix + " ";
                    result += (String.IsNullOrEmpty(LastName)) ? "" : LastName + " ";
                    result += Suffix;
                    break;
                case NameFormat.FirstLastShort:
                    result = (String.IsNullOrEmpty(GivenName)) ? "" : GivenName + " ";
                    result += LastName;
                    break;
                case NameFormat.LastFirstShort:
                    result = (String.IsNullOrEmpty(LastName)) ? "" : LastName + " ";
                    result += GivenName;
                    break;
                case NameFormat.LastFirstLong:
                    result = (String.IsNullOrEmpty(LastNamePrefix)) ? "" : LastNamePrefix + " ";
                    result += (String.IsNullOrEmpty(LastName)) ? "" : LastName + " ";
                    result += (String.IsNullOrEmpty(Prefix)) ? "" : Prefix + " ";
                    result += (String.IsNullOrEmpty(GivenName)) ? "" : GivenName + " ";
                    result += (String.IsNullOrEmpty(NickName)) ? "" : " {" + NickName + "} ";
                    result += Suffix;
                    break;
            }
            return result;
        }

        /// <summary>
        /// Provides a string representation of the Name object based on a tokenised
        /// format string
        /// </summary>
        /// <param name="formatString">The token based format string to use</param>
        /// <returns>The formatted string</returns>
        public string ToString(string formatString)
        {
            Regex match = new Regex(@"g|l|n|p|s|x", RegexOptions.IgnoreCase);
            return match.Replace(formatString, EvaluateFormatToken);
        }

        #endregion

        #region Public Static Operators

        public static implicit operator string(Name n)
        {
            return n.ToString();
        }

        #endregion

        #region IComparable Members

        /// <summary>
        /// Compares this instance with another Name object
        /// </summary>
        /// <param name="obj">The Name object to compare to</param>
        /// <returns>-ve, 0 or +ve</returns>
        public int CompareTo(object obj)
        {
            if (obj is Name)
                return CompareTo((Name)obj);
            else
                return 1;
        }

        #endregion

        #region IComparable<Name> Members

        public int CompareTo(Name other)
        {
            //Compare based on the Last Names
            int retValue = LastName.CompareTo(other.LastName);

            if (retValue == 0)
            {
                //Compare based on Given Names
                retValue = GivenName.CompareTo(other.GivenName);
            }

            return retValue;
        }

        #endregion

        #region IEquatable<Name> Members

        public bool Equals(Name other)
        {
            return ((GivenName == other.GivenName) && (LastName == other.LastName) &&
                (NickName == other.NickName) && (Prefix == other.Prefix) && (Suffix == other.Suffix) &&
                (LastNamePrefix == other.LastNamePrefix));
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            return new Name(this.Prefix, this.GivenName, this.LastNamePrefix, this.LastName, this.Suffix, this.NickName);
        }

        #endregion

        #region IFormattable Members

        public string ToString(string format, IFormatProvider formatProvider)
        {
            switch (format.ToLower())
            {
                case "l": return this.ToString(NameFormat.LastFirstShort);
                case "L": return this.ToString(NameFormat.LastFirstLong);
                case "g": return this.ToString(NameFormat.FirstLastShort);
                case "G": return this.ToString(NameFormat.FirstLastLong);
                default: return this.ToString();
            }
        }

        #endregion

    }
}